﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Serialization;
using AviationSimulator.GUI;
using AviationSimulator.Interfaces;
using AviationSimulator.Properties;

namespace AviationSimulator.DataItems.Mode.Send
{
    public class MathFunctionMode : SendModeBase, IModeDataTableParametrizable, IModeSerializable
    {
        public List<ParameterFunction> ParameterFunctions { get; set; }
        public DataTable DataTable;

        public MathFunctionMode()
        {
            ParameterFunctions = new List<ParameterFunction>();

            DataTable = new DataTable();
            DataTable.Columns.Add("Parameter");
            DataTable.Columns.Add("Function");
        }

        public void AddParameter(string parameterName)
        {
            var parameterIsInList = ParameterFunctions.Where(parameterFunction =>
                                                             parameterFunction.ParameterName == parameterName).Count() !=
                                                             0;

            if (parameterIsInList)
            {
                MessageBox.Show(Resources.ParameterInListMessage);
                
                return;
            }

            ParameterFunctions.Add(new ParameterFunction
                                       {
                                           MathFunction = null,
                                           ParameterName = parameterName
                                       });

            var dataRow = DataTable.NewRow();
            dataRow[0] = parameterName;

            DataTable.Rows.Add(dataRow);
        }

        public void RemoveParameter(int parameterIndex)
        {
            var parameterName = DataTable.Rows[parameterIndex][0].ToString();

            try
            {
                var function =
                ParameterFunctions.Single(
                    parameterFunction => parameterFunction.ParameterName.Equals(parameterName));

                ParameterFunctions.Remove(function);
            }
            catch (InvalidOperationException)
            {
            }

            DataTable.Rows.RemoveAt(parameterIndex);
        }

        public void EditParameterFunction(int parameterFunctionIndex)
        {
            try
            {
                var parameterName = DataTable.Rows[parameterFunctionIndex][0].ToString();
                var mathForm = new EditMathFunction(ParameterFunctions, parameterName);

                if (mathForm.ShowDialog() == DialogResult.OK)
                {
                    var mathFunctionName =
                        ParameterFunctions.Single(parameterFunction =>
                            parameterFunction.ParameterName == parameterName)
                            .MathFunction.Name;

                    DataTable.Rows[parameterFunctionIndex][1] = mathFunctionName;
                }
            }
            catch (IndexOutOfRangeException)
            {
            }
        }

        public void Serialize(string filePath)
        {
            var modeToSerialize = new MathFunctionModeSerializable
                                      {
                                          Address = Address,
                                          Port = Port,
                                          Period = Period,
                                          SendPeriodically = SendPeriodically,
                                          ParameterFunctions = ParameterFunctions
                                      };

            var serializer = new XmlSerializer(typeof(MathFunctionModeSerializable));

            using (var streamWriter = new StreamWriter(filePath))
            {
                serializer.Serialize(streamWriter, modeToSerialize);
            }
        }

        public void Deserialize(string filePath)
        {
            var deserializer = new XmlSerializer(typeof(MathFunctionModeSerializable));
            MathFunctionModeSerializable modeToDeserialize;

            try
            {
                using (var streamReader = new StreamReader(filePath))
                {
                    modeToDeserialize = (MathFunctionModeSerializable)deserializer.Deserialize(streamReader);
                }
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show(Resources.CantLoadModeParameters);
                return;
            }
            
            if (modeToDeserialize == null) return;

            Address = modeToDeserialize.Address;
            Port = modeToDeserialize.Port;
            SendPeriodically = modeToDeserialize.SendPeriodically;
            Period = modeToDeserialize.Period;
            ParameterFunctions = modeToDeserialize.ParameterFunctions;

            UpdateDataTable();
        }

        private void UpdateDataTable()
        {
            DataTable.Clear();

            foreach (var parameterFunction in ParameterFunctions)
            {
                var dataRow = DataTable.NewRow();
                dataRow[0] = parameterFunction.ParameterName;
                dataRow[1] = parameterFunction.MathFunction.Name;

                DataTable.Rows.Add(dataRow);
            }
        }

        public Package GeneratePackage()
        {
            var package = new Package();

            foreach (var parameterFunction in ParameterFunctions)
            {
                var value = parameterFunction.MathFunction.GenerateParameterValue();
                package.Parameters.Add(new Parameter 
                                           { 
                                               Name = parameterFunction.ParameterName, 
                                               Value = value.ToString()
                                           });
            }

            return package;
        }

    }
}
